package cn.itcast.nems.enrol.service.impl;

import cn.itcast.ic.common.exception.v2.BizExceptionProducer;
import cn.itcast.ic.common.exception.v2.bean.BizStatusEnum;
import cn.itcast.nems.base.dao.mapper.PreStudentInfoMapper;
import cn.itcast.nems.common.enumeration.BizNumberTypeEnum;
import cn.itcast.nems.common.service.BizNumberService;
import cn.itcast.nems.discount.api.DiscountApi;
import cn.itcast.nems.discount.dto.DiscountSummaryDTO;
import cn.itcast.nems.enrol.api.EnrolApi;
import cn.itcast.nems.enrol.command.EnrolQuickCmd;
import cn.itcast.nems.enrol.converter.ActivityCourseConverter;
import cn.itcast.nems.enrol.converter.EnrolConverter;
import cn.itcast.nems.enrol.dto.*;
import cn.itcast.nems.enrol.service.ActivityCourseService;
import cn.itcast.nems.enrol.service.EnrolQuickService;
import cn.itcast.nems.manager.redis.RedisUtil;
import cn.itcast.nems.manager.scrm.SCRMManager;
import cn.itcast.nems.manager.scrm.dto.CollegeClue;
import cn.itcast.nems.manager.scrm.dto.CollegeClueAddResult;
import cn.itcast.nems.order.dao.dataobject.OrderLinkDO;
import cn.itcast.nems.order.dao.mapper.OrderMapper;
import cn.itcast.nems.product.api.ProductApi;
import cn.itcast.nems.product.api.TuitionFeeApi;
import cn.itcast.nems.product.dao.dataobject.BizNo;
import cn.itcast.nems.product.dto.ProductDTO;
import cn.itcast.nems.product.dto.TuitionFeeDTO;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * author liyong
 * create: 2024-04-14 09:40:08
 **/
@Service
public class EnrolQuickServiceImpl implements EnrolQuickService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final EnrolApi enrolApi;
    private final SCRMManager scrmManager;
    private final EnrolQuickConfig enrolQuickConfig;
    private final BizNumberService bizNumberService;
    private final DiscountApi discountApi;
    private final ProductApi productApi;
    private final TuitionFeeApi tuitionFeeApi;
    private final PreStudentInfoMapper preStudentInfoMapper;
    private final OrderMapper orderMapper;
    private final ActivityCourseService activityCourseService;
    private final RedisUtil redisUtil;
    private final ObjectMapper objectMapper = new ObjectMapper();

    public EnrolQuickServiceImpl(EnrolApi enrolApi,
                                 SCRMManager scrmManager,
                                 EnrolQuickConfig enrolQuickConfig,
                                 BizNumberService bizNumberService,
                                 DiscountApi discountApi,
                                 ProductApi productApi,
                                 TuitionFeeApi tuitionFeeApi,
                                 PreStudentInfoMapper preStudentInfoMapper,
                                 OrderMapper orderMapper,
                                 ActivityCourseService activityCourseService,
                                 RedisUtil redisUtil) {
        this.enrolApi = enrolApi;
        this.scrmManager = scrmManager;
        this.enrolQuickConfig = enrolQuickConfig;
        this.bizNumberService = bizNumberService;
        this.discountApi = discountApi;
        this.productApi = productApi;
        this.tuitionFeeApi = tuitionFeeApi;
        this.preStudentInfoMapper = preStudentInfoMapper;
        this.orderMapper = orderMapper;
        this.activityCourseService = activityCourseService;
        this.redisUtil = redisUtil;
    }

    @Override
    public EnrolQuickResultDTO enrol(EnrolQuickCmd quickEnrol) {
        final ActivityConfig config = this.enrolQuickConfig.findActivityConfig(quickEnrol.getActivitCode());
        if (config == null) {
            logger.warn("没有找到活动'{}'配置信息！", quickEnrol.getActivitCode());
            BizExceptionProducer.throwBadRequest(BizStatusEnum.BAD_REQUEST.name(), "没有找到活动'%s'配置信息！", quickEnrol.getActivitCode());
        }
        final ActivityCourseDTO course = this.activityCourseService.findActivityCourse(quickEnrol.getSchoolId(), quickEnrol.getSubjectId());
        if (course == null) {
            logger.warn("没有找到活动'{}'配置的校区'{}',学科'{}'信息！",
                    quickEnrol.getActivitCode(), quickEnrol.getSchoolId(), quickEnrol.getSubjectId());
            BizExceptionProducer.throwBadRequest(BizStatusEnum.BAD_REQUEST.name(), "没有找到活动'%s'配置的校区'%s',学科'%s'信息！",
                    quickEnrol.getActivitCode(), quickEnrol.getSchoolId(), quickEnrol.getSubjectId());
        }
        logger.info("{} courseConfig: {} ", quickEnrol.getActivitCode(), course);

        final CollegeClueAddResult ccAddResult = this.createCustomer(quickEnrol, config);
        ccAddResult.setName(quickEnrol.getName());
        logger.info("{} CollegeClueAddResult: {} ", quickEnrol.getActivitCode(), ccAddResult);

        EnrolQuickResultDTO result = this.getSigupLink(quickEnrol, course, ccAddResult);
        if (result != null) {
            return result;
        }

        EnrolFormDTO enrol = this.createEnrolFormDTO(quickEnrol, course, ccAddResult);
        logger.info("{} enrol before: {} ", quickEnrol.getActivitCode(), enrol);
        enrol = enrolApi.confirmStudentInfo(enrol);
        logger.info("{} enrol after: {} ", quickEnrol.getActivitCode(), enrol);
        String url = enrol.getOrder().getPayUrl();
        logger.info("{} enrol url: {} ", quickEnrol.getActivitCode(), url);
        return new EnrolQuickResultDTO(url);
    }

    @Override
    public List<SchoolSubjectDTO> findSchoolSubject(String activityCode) {
        String key = "NEMS:ENROL:QUICK:" + activityCode;
        try {
            String cacahed = (String) this.redisUtil.get(key);
            if (StringUtils.hasText(cacahed)) {
                return objectMapper.readValue(cacahed, List.class);
            }
        } catch (Exception e) {
            logger.warn(e.getMessage(), e);
        }
        List<SchoolSubjectDTO> result = this.activityCourseService
                .findActivityCourses(activityCode)
                .stream().map(ActivityCourseConverter::dtoToSchoolSubject).toList();
        try {
            long time = 60 * 10;
            final String str = objectMapper.writeValueAsString(result);
            this.redisUtil.set(key, str, time);
        } catch (Exception e) {
            logger.warn(e.getMessage(), e);
        }
        return result;
    }

    private EnrolFormDTO createEnrolFormDTO(EnrolQuickCmd quickEnrol,
                                            ActivityCourseDTO course,
                                            CollegeClueAddResult ccAddResult) {
        String bizOrderNo = this.bizNumberService.next(BizNumberTypeEnum.ENROL_QUICK);
        final Integer clazzId = course.getClazzId();
        TuitionFeeDTO tuitionFee = this.tuitionFeeApi.findTuition(clazzId);
        logger.info("clazzId: {} tuitionFeeId: {} first: {} last: {}",
                clazzId, tuitionFee.getId(), tuitionFee.getFirst(), tuitionFee.getLast());
        BigDecimal fee = tuitionFee.getFirst();
        ProductDTO product = this.findProductDTO(clazzId);
        product.setPrice(fee.intValue() * 100);
        logger.info("{} product: {} ", quickEnrol.getActivitCode(), product);
        List<EnrolDiscountDTO> discountList = this.findDiscounts(course.getDiscountIdList());
        logger.info("discountList: {}", discountList);
        EnrolFormDTO enrol = EnrolConverter.comandToQuickForm(ccAddResult,
                course,
                tuitionFee.getId(),
                product,
                discountList,
                bizOrderNo);
        OrderLinkDO orderLinkDO = orderMapper.findPendingList(String.valueOf(ccAddResult.getMdid()));
        if (orderLinkDO != null) {
            logger.info("customerId:{} mdid:{} 修改报名订单: {}", ccAddResult.getCid(), ccAddResult.getMdid(), orderLinkDO);
            enrol.getOrder().setOrderNo(orderLinkDO.getOrderNo());
        }
        return enrol;
    }

    // 检查客户是否已经报过该班
    private EnrolQuickResultDTO getSigupLink(EnrolQuickCmd quickEnrol,
                                             ActivityCourseDTO course,
                                             CollegeClueAddResult ccAddResult) {
        final Integer clazzId = course.getClazzId();
        final Integer cid = ccAddResult.getCid();
        if (cid != null) {
            final String sigupLink = this.preStudentInfoMapper.selectPayLink(cid, clazzId);
            if (StringUtils.hasText(sigupLink)) {
                logger.info("客户 {} customerId: {} clazzId: {} 已经支付 payLink: {}", quickEnrol.getMobile(), cid, clazzId, sigupLink);
                return new EnrolQuickResultDTO(sigupLink);
            }
        }
        return null;
    }

    private ProductDTO findProductDTO(Integer clazzId) {
        final String bizNo = BizNo.calBizNo(clazzId);
        return this.productApi.findProductByIdOrBizNo(null, bizNo);
    }

    private List<EnrolDiscountDTO> findDiscounts(List<Integer> discountIds) {
        if (discountIds != null && !discountIds.isEmpty()) {
            final Set<String> ids = discountIds.stream().map(String::valueOf).collect(Collectors.toSet());
            final Set<DiscountSummaryDTO> summaryByIds = this.discountApi.getSummaryByIds(ids);
            return summaryByIds.stream().map((ds -> {
                EnrolDiscountDTO d = new EnrolDiscountDTO();
                d.setDiscountId(ds.getId().longValue());
                d.setDiscountMoney(ds.getAmount());
                d.setDiscountName(ds.getName());
                return d;
            })).toList();
        }
        return Collections.emptyList();
    }

    /**
     * 创建客户
     *
     * @return 客户ID
     */
    private CollegeClueAddResult createCustomer(EnrolQuickCmd cmd, ActivityConfig config) {
        CollegeClue cc = EnrolConverter.comandToClue(cmd, config);
        return this.scrmManager.addCollegeClue(cc);
    }
}
